package com.punai.dataanalysis.srlib.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.multi.ListValueMap;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.punai.common.core.domain.TreeBo;
import com.punai.config.sqlitedao.IndicatorItemRepository;
import com.punai.config.sqlitedao.StructureLinkItemRepository;
import com.punai.config.sqlitedao.StructureRepository;
import com.punai.config.sqlitedao.TemplateRepository;
import com.punai.config.sqlitedomain.ConfigIndicatorItem;
import com.punai.config.sqlitedomain.Structure;
import com.punai.config.sqlitedomain.StructureLinkItem;
import com.punai.config.sqlitedomain.Template;
import com.punai.dataanalysis.other.mapper.OtherModuleMapper;
import com.punai.dataanalysis.srlib.bo.SrIndicatorBo;
import com.punai.dataanalysis.srlib.bo.SrIndicatorDetailBo;
import com.punai.dataanalysis.srlib.service.SrIndicatorService;
import com.punai.dataanalysis.srlib.vo.SrIndicatorVo;
import com.punai.externalccb.domain.EcoZbstructitem;
import com.punai.externalccb.mapper.EcoZbstructitemMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SrIndicatorServiceImpl implements SrIndicatorService {

    @Autowired
    private TemplateRepository templateRepository;
    @Autowired
    private StructureRepository structureRepository;
    @Autowired
    private StructureLinkItemRepository structureLinkItemRepository;
    @Autowired
    private IndicatorItemRepository indicatorItemRepository;
    @Autowired
    private EcoZbstructitemMapper zbstructitemMapper;
    @Autowired
    private OtherModuleMapper otherModuleMapper;


    @Override
    public List<TreeBo> templateStructTree() {
        List<TreeBo> res = new ArrayList<>();
        TreeBo root = new TreeBo();
        root.setId("0");
        root.setType("0");
        root.setName("模板结构");
        res.add(root);
        // 0 收入指标
        List<Template> templates = templateRepository.findAllByType("0");
        if (CollUtil.isNotEmpty(templates))  {
            // 收入指标的结构
            for (Template template : templates) {
                String id = template.getId();
                TreeBo templateTree = new TreeBo();
                templateTree.setId(id);
                templateTree.setType("1");
                templateTree.setName(template.getName());
                root.getChildren().add(templateTree);
                List<Structure> structures = structureRepository.findByTemplateId(id);
                if (CollUtil.isNotEmpty(structures)) {
                    for (Structure structure : structures) {
                        TreeBo structureTree = new TreeBo();
                        structureTree.setId(structure.getId());
                        structureTree.setType("2");
                        structureTree.setName(structure.getName());
                        templateTree.getChildren().add(structureTree);
                    }
                }
            }
        }
        return res;
    }

    @Override
    public List<SrIndicatorBo> getIndicatorList(SrIndicatorVo vo) {

        String name = vo.getName();
        String structId = vo.getStructId();
        List<StructureLinkItem> structureLinkItems = structureLinkItemRepository.findByStrutsId(structId);

        List<String> itemIds = structureLinkItems.stream().map(StructureLinkItem::getElementId).collect(Collectors.toList());

        List<ConfigIndicatorItem> configIndicatorItems = indicatorItemRepository.findByIdIn(itemIds);

        Map<String,ConfigIndicatorItem> indicatorItemMap = new HashMap<>();
        for (ConfigIndicatorItem configIndicatorItem : configIndicatorItems) {
            indicatorItemMap.put(configIndicatorItem.getId(),configIndicatorItem);
        }


        ListValueMap<String,StructureLinkItem> levelMap = new ListValueMap<>();
        for (StructureLinkItem structureLinkItem : structureLinkItems) {
            String elementPid = structureLinkItem.getElementPid();
            if (StrUtil.isBlank(elementPid)) {
                elementPid = "0";
            }
            levelMap.putValue(elementPid,structureLinkItem);
        }

        List<StructureLinkItem> roots = levelMap.get("0");
        List<SrIndicatorBo> res = new ArrayList<>();
        if (CollUtil.isEmpty(roots)) {
            return res;
        }
        roots.sort(Comparator.comparingInt(StructureLinkItem::getSorting));

        Set<String> ids = new HashSet<>();
        List<String> linkIdList = new ArrayList<>();
        for (StructureLinkItem root : roots) {
            String pids = "";
            String elementId = root.getElementId();
            ConfigIndicatorItem configIndicatorItem = indicatorItemMap.get(elementId);
            if (configIndicatorItem == null) {
                continue;
            }
            SrIndicatorBo srIndicatorBo = new SrIndicatorBo();
            srIndicatorBo.setId(elementId);
            srIndicatorBo.setStructId(root.getStrutsId());
            srIndicatorBo.setName(configIndicatorItem.getName());
            srIndicatorBo.setUnit(configIndicatorItem.getUnit());
            if (StrUtil.contains(configIndicatorItem.getName(),name)) {
                ids.add(elementId);
            }
            pids += "," + elementId;
            setChildren(srIndicatorBo,vo,levelMap,indicatorItemMap,pids,linkIdList,ids);
            res.add(srIndicatorBo);
        }
        if (StrUtil.isNotBlank(name)) {
            Set<String> parnetIds = new HashSet<>();
            for (String id : ids) {
                for (String linkIds : linkIdList) {
                    if (StrUtil.contains(linkIds,id)) {
                        int i = linkIds.indexOf(id);
                        if (i != 1) {
                            String pids = linkIds.substring(1, i-1);
                            List<String> pidList = StrUtil.split(pids, ",");
                            parnetIds.addAll(pidList);
                        }
                    }
                }
            }
            // 路径id
            ids.addAll(parnetIds);
            // 移除不符合条件的
            Iterator<SrIndicatorBo> iterator = res.iterator();
            while (iterator.hasNext()) {
                SrIndicatorBo next = iterator.next();
                if (!ids.contains(next.getId())) {
                    iterator.remove();
                } else {
                    List<SrIndicatorBo> children = next.getChildren();
                    removeChildren(children,ids);
                }
            }
        }

        // 处理 平均值 / 区间值
        for (SrIndicatorBo bo : res) {
            String elementId = bo.getId();
            List<EcoZbstructitem> structItems = zbstructitemMapper.selectList(
                    Wrappers.<EcoZbstructitem>lambdaQuery()
                            .eq(EcoZbstructitem::getStructid, bo.getStructId())
                            .eq(EcoZbstructitem::getZbid, elementId)
            );

            List<BigDecimal> list = structItems.stream().map(EcoZbstructitem::getDwzj).filter(Objects::nonNull).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(list)) {
                BigDecimal avgValue = list.stream().filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.valueOf(list.size()), 3, RoundingMode.HALF_UP);
                BigDecimal max = list.stream().max(Comparator.comparing(x -> x)).orElse(BigDecimal.ZERO);
                BigDecimal min = list.stream().min(Comparator.comparing(x -> x)).orElse(BigDecimal.ZERO);
                bo.setAvgPrice(avgValue);
                bo.setPriceRange(min.setScale(3, RoundingMode.HALF_UP) + "-" + max.setScale(3, RoundingMode.HALF_UP));
            }
        }
        return res;
    }

    @Override
    public List<SrIndicatorDetailBo> getStructIndicatorDetailList(SrIndicatorVo vo) {
        // 查询指标详情
        String structId = vo.getStructId();
        String indicatorId = vo.getId();
        return otherModuleMapper.selectBos(structId,indicatorId);
    }

    private void removeChildren(List<SrIndicatorBo> children, Set<String> ids) {
        if (CollUtil.isNotEmpty(children)) {
            Iterator<SrIndicatorBo> iterator = children.iterator();
            while (iterator.hasNext()) {
                SrIndicatorBo next = iterator.next();
                if (!ids.contains(next.getId())) {
                    iterator.remove();
                } else {
                    removeChildren(next.getChildren(),ids);
                }
            }
        }
    }

    private void setChildren(SrIndicatorBo srIndicatorBo,SrIndicatorVo vo, ListValueMap<String, StructureLinkItem> levelMap,
                             Map<String, ConfigIndicatorItem> indicatorItemMap,String pids,List<String> linkIdList,Set<String> ids) {
        String id = srIndicatorBo.getId();
        List<StructureLinkItem> structureLinkItems = levelMap.get(id);
        if (CollUtil.isNotEmpty(structureLinkItems)) {
            structureLinkItems.sort(Comparator.comparingInt(StructureLinkItem::getSorting));
            for (StructureLinkItem structureLinkItem : structureLinkItems) {
                String elementId = structureLinkItem.getElementId();
                ConfigIndicatorItem configIndicatorItem = indicatorItemMap.get(elementId);
                if (configIndicatorItem == null) {
                    continue;
                }
                SrIndicatorBo srIndicatorBo1 = new SrIndicatorBo();
                srIndicatorBo1.setId(elementId);
                srIndicatorBo1.setStructId(structureLinkItem.getStrutsId());
                srIndicatorBo1.setName(configIndicatorItem.getName());
                srIndicatorBo1.setUnit(configIndicatorItem.getUnit());
                if (StrUtil.contains(configIndicatorItem.getName(),vo.getName())) {
                    ids.add(elementId);
                }
                String cpids =  pids + "," + elementId;
                setChildren(srIndicatorBo1,vo,levelMap,indicatorItemMap,cpids,linkIdList,ids);
                srIndicatorBo.getChildren().add(srIndicatorBo1);
            }
        } else {
            linkIdList.add(pids);
        }
    }
}
